package cn.juque.jdfsystem.task;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;
import cn.juque.jdfsystem.cache.RegisterInfoCache;
import cn.juque.jdfsystem.config.JdfConfig;
import cn.juque.jdfsystem.entity.RegisterInfo;
import cn.juque.jdfsystem.enums.RegisterExecuteStatusEnum;
import cn.juque.jdfsystem.helper.ConfigInfoHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;

import javax.annotation.Resource;
import java.util.Map;
import java.util.OptionalInt;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>AbstractTask</li>
 * </ul>
 * @date 2023-01-11 00:20:35
 **/
@Slf4j
public abstract class AbstractTask {

    private static final String NAME = "AbstractTask";

    @Resource
    protected JdfConfig jdfConfig;

    @Resource
    protected RegisterInfoCache registerInfoCache;

    @Resource
    protected ConfigInfoHelper configInfoHelper;

    /**
     * 开始执行
     *
     * @param args 参数
     */
    @Async("jdfExecutor")
    public void start(String[] args) {
        if (!this.before()) {
            return;
        }
        Integer sleep = this.initSleepTimes();
        if (null != sleep) {
            sleep = sleep <= 1 ? 2 : sleep;
            int seconds = RandomUtil.randomInt(1, sleep);
            log.info("{}任务等待时长:{}s", this.getTaskName(), sleep);
            ThreadUtil.sleep(seconds * 1000L);
        }
        // 执行业务逻辑
        this.execute(args);
    }

    /**
     * 任务开始前的操作
     *
     * @return true 可以继续往下执行；false 相反
     */
    public boolean before() {
        // 没有初始化完成
        return Boolean.TRUE.equals(this.jdfConfig.getInitComplete());
    }

    /**
     * 任务逻辑
     *
     * @param args 参数
     */
    public abstract void execute(String[] args);

    /**
     * 设置随机休眠等待最大时长 单位：秒
     *
     * @return 秒
     */
    protected abstract Integer initSleepTimes();

    protected String getTaskName() {
        return NAME;
    }

    /**
     * 检查当前节点是否可以执行当前操作
     *
     * @return true=可执行；false=不可执行
     */
    protected Boolean checkExecuteNode() {
        Map<String, RegisterInfo> map = this.registerInfoCache.getAllRegister();
        OptionalInt optionalInt = map.values().stream()
                .filter(f -> !RegisterExecuteStatusEnum.DOWN_LINE.getCode().equals(f.getExecuteStatus()))
                .mapToInt(m -> m.getNodeName().hashCode()).max();
        if (!optionalInt.isPresent()) {
            return false;
        }
        int maxHashCode = optionalInt.getAsInt();
        String nodeName = this.jdfConfig.getNodeName();
        // 判断当前节点hashCode值，非最大值，则不允许执行数据库操作
        Map<Integer, String> hashCodeMap = this.registerInfoCache.getAllNodeName();
        return CharSequenceUtil.equals(nodeName, hashCodeMap.get(maxHashCode));
    }
}
